package com.only4play.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.only4play.common.PasswordGenerator;
import com.only4play.common.constants.ErrorCodeEnum;
import com.only4play.common.exception.ApplicationException;
import com.only4play.common.model.entity.RowStatus;
import com.only4play.domain.entity.UserPersonEntity;
import com.only4play.domain.entity.UserPersonalAccountEntity;
import com.only4play.dto.PersonRegisterDto;
import com.only4play.idgenerator.provider.IdGenerator;
import com.only4play.mapper.UserPersonMapper;
import com.only4play.mapper.UserPersonalAccountMapper;
import com.only4play.service.UserPersonalAccountService;
import com.only4play.utils.converter.UserPersonConverter;
import com.only4play.vo.UserPersonAccountVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @author liyuncong
 * @version 1.0
 * @file UserPersonalAccountServiceImpl
 * @brief 用户账号服务实现
 * @details 用户账号服务实现
 * @date 2023-11-18
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2023-11-18               liyuncong          Created
 */
@Service
public class UserPersonalAccountServiceImpl
    extends ServiceImpl<UserPersonalAccountMapper, UserPersonalAccountEntity>
    implements UserPersonalAccountService {

    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private PasswordGenerator passwordGenerator;
    @Autowired
    private UserPersonConverter personConverter;
    @Autowired
    private UserPersonMapper personMapper;
    @Autowired
    private UserPersonalAccountMapper personalAccountMapper;


    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Boolean register(PersonRegisterDto registerDto) {
        try {
            UserPersonEntity personEntity = personConverter.fromRegisterDto(registerDto);
            // save person info
            personEntity.setId(idGenerator.newString());
            personMapper.insert(personEntity);
            UserPersonalAccountEntity accountEntity = personConverter.fromRegisterDto(registerDto, passwordGenerator, passwordEncoder);
            accountEntity.setId(idGenerator.newString());
            accountEntity.setPerson(personEntity);
            accountEntity.setUserPersonId(personEntity.getId());
            // save account info
            personalAccountMapper.insert(accountEntity);
        } catch (Exception exception) {
            throw new ApplicationException(ErrorCodeEnum.SAVE_ERROR, exception);
        }
        return true;
    }

    @Override
    public UserPersonAccountVo queryByLoginUsername(String loginUsername) {
        // query account
        LambdaQueryWrapper<UserPersonalAccountEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserPersonalAccountEntity::getLoginUsername, loginUsername)
            .eq(UserPersonalAccountEntity::getRowStatus, RowStatus.OK);
        UserPersonalAccountEntity account = personalAccountMapper.selectOne(wrapper);
        if (Objects.isNull(account)) {
            throw new ApplicationException(ErrorCodeEnum.NOT_FOUND_ERROR);
        }

        // query basic details
        UserPersonEntity person = personMapper.selectById(account.getUserPersonId());
        if (Objects.isNull(person)) {
            throw new ApplicationException(ErrorCodeEnum.NOT_FOUND_ERROR);
        }
        account.setPerson(person);
        return personConverter.toUserPersonAccountVo(account);
    }

    @Override
    public Boolean authenticate(String loginUsername, String loginPassword) {
        LambdaQueryWrapper<UserPersonalAccountEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserPersonalAccountEntity::getLoginUsername, loginUsername)
            .eq(UserPersonalAccountEntity::getRowStatus, RowStatus.OK);
        UserPersonalAccountEntity entity = personalAccountMapper.selectOne(wrapper);
        if (Objects.isNull(entity)) {
            throw new ApplicationException(ErrorCodeEnum.NOT_FOUND_ERROR);
        }
        return passwordGenerator.verify(loginUsername, loginPassword,
            entity.getLoginPasswordSalt(), entity.getLoginPassword(), passwordEncoder);
    }
}
